home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / pascal / xlibpas2.zip / XGIF2.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-06-12  |  17.4 KB  |  756 lines

  1. unit XGIF2;
  2. { ************************************************
  3.   **    GIF Decoding and Encoding procedures    **
  4.   **        for Borland/Turbo Pascal 7.0        **
  5.   **                                            **
  6.   **     Written by Tristan Tarrant, 1994       **
  7.   **                                            **
  8.   **        ( Supports GIF87a/GIF89a )          **
  9.   ************************************************ }
  10.  
  11. interface
  12.  
  13. uses
  14.     Dos;
  15.  
  16. const
  17.     { Error constants used in GIF decoder }
  18.     GoodRead      = 0;
  19.     BadFile       = 1;
  20.     BadRead       = 2;
  21.     UnexpectedEOF = 3;
  22.     BadCode       = 4;
  23.     BadFirstCode  = 5;
  24.     NoFile        = 6;
  25.     BadSymbolSize = 7;
  26.     NoCode        = -1;
  27.     Gif87a        = 0;
  28.     Gif89a        = 1;
  29.  
  30.     { These values will be masked with the codes output from the
  31.         decoder to remove spurious bits }
  32.     CodeMask : array[1..13] of word =
  33.         ( $0000,
  34.             $0001, $0003,
  35.             $0007, $000F,
  36.             $001F, $003F,
  37.             $007F, $00FF,
  38.             $01FF, $03FF,
  39.             $07FF, $0FFF );
  40.  
  41. Type
  42.     GifLineProcType = procedure( Var pixels; line, width : integer );
  43.     GifPixelProcType = function : integer;
  44.     TByteArray = Array[0..0] of byte;
  45.     TIntArray = Array[0..0] of integer;
  46.  
  47. Var
  48.     { Pointers to custom procedures to deal with lines. GifOutLineProc
  49.       is called with three parameters : an untyped var, containing
  50.       the uncompressed data, and two integer values, containing the
  51.       line number and the width of the line.
  52.       GifInPixelProc should instead return a pixels value, -1 if at the
  53.       end of the data. }
  54.  
  55.     GifOutLineProc : GifLineProcType;
  56.     GifInPixelProc : GifPixelProcType;
  57.     GifPalette : array[0..767] of byte;
  58.  
  59.  
  60.  
  61. function LoadGif( f : string ) : integer;
  62. function SaveGif( f : string; width, depth, bits : integer; var palette ) : integer;
  63. function GifError( ErrorCode : integer ) : string;
  64.  
  65. Implementation
  66.  
  67. type
  68.     GifHeader =
  69.         record
  70.             sig : array[1..6] of char;
  71.             screenwidth, screendepth : word;
  72.             flags, background, aspect : byte;
  73.         end;
  74.  
  75.     ImageBlock =
  76.         record
  77.             left, top, width, depth : word;
  78.             flags : byte;
  79.         end;
  80.  
  81.     FileInfo =
  82.         record
  83.             width, depth, bits,
  84.             flags, background : integer;
  85.             palette : array[1..768] of byte;
  86.         end;
  87.  
  88.     ControlBlock =
  89.         record
  90.             blocksize, flags : byte;
  91.             delay : word;
  92.             transparentcolour, terminator : byte;
  93.         end;
  94.  
  95.     PlainText =
  96.         record
  97.             blocksize : byte;
  98.             left, top, gridwidth, gridheight : word;
  99.             cellwidth, cellheight, forecolour, backcolour : byte;
  100.         end;
  101.  
  102.     Application =
  103.         record
  104.             blocksize : byte;
  105.             applstring : array[1..8] of char;
  106.             authentication : array[1..3] of char;
  107.         end;
  108.  
  109.  
  110. const
  111.     TableSize = 5003;
  112.     LargestCode = 4095;
  113.  
  114. function UnpackImage( var F : File; bits : integer; Var fi : FileInfo ) : integer;
  115. var
  116.     bits2, codesize, codesize2, nextcode, thiscode,
  117.     oldtoken, currentcode, oldcode, bitsleft, blocksize,
  118.     line, pass, byt, p, q, u : integer;
  119.     b : array[0..255] of byte;
  120.     linebuffer, firstcodestack, lastcodestack : ^TByteArray;
  121.     codestack : ^TIntArray;
  122. const
  123.     wordmasktable : array[0..15] of word =
  124.         ( $0000, $0001, $0003, $0007, $000F, $001F,
  125.             $003F, $007F, $00FF, $01FF, $03FF, $07FF,
  126.             $0FFF, $1FFF, $3FFF, $7FFF );
  127.     inctable : array[0..4] of integer = ( 8, 8, 4, 2, 0 );
  128.     starttable : array[0..4] of integer = ( 0, 4, 2, 1, 0 );
  129. begin
  130.     pass := 0;
  131.     line := 0;
  132.     byt := 0;
  133.     p := 0;
  134.     q := 0;
  135.     blocksize := 0;
  136.     fillchar( b, 256, 0 );
  137.     bitsleft := 8;
  138.     if ( bits < 2 ) or ( bits > 8 ) then
  139.     begin
  140.         UnpackImage := BadSymbolSize;
  141.         exit;
  142.     end;
  143.     bits2 := 1 shl bits;
  144.     nextcode := bits2 + 2;
  145.     codesize := bits + 1;
  146.     codesize2 := 1 shl codesize;
  147.     oldcode := NoCode;
  148.     oldtoken := NoCode;
  149.     getmem( firstcodestack, 4096 );
  150.     getmem( lastcodestack, 4096 );
  151.     getmem( codestack, 8192 );
  152.     getmem( linebuffer, fi.width );
  153.     while true do
  154.     begin
  155.         if bitsleft = 8 then
  156.         begin
  157.             inc(p);
  158.             if p>=q then
  159.             begin
  160.                 blocksize := 0;
  161.                 blockread( F, blocksize, 1);
  162.                 if blocksize>0 then
  163.                 begin
  164.                     p:=0;
  165.                     blockread( F, b, blocksize, q );
  166.                     if q<>blocksize then
  167.                     begin
  168.                         freemem( firstcodestack, 4096 );
  169.                         freemem( lastcodestack, 4096 );
  170.                         freemem( codestack, 8192 );
  171.                         freemem( linebuffer, fi.width );
  172.                         UnpackImage := UnexpectedEOF;
  173.                         exit;
  174.                     end;
  175.                 end else
  176.                 begin
  177.                     freemem( firstcodestack, 4096 );
  178.                     freemem( lastcodestack, 4096 );
  179.                     freemem( codestack, 8192 );
  180.                     freemem( linebuffer, fi.width );
  181.                     UnpackImage := UnexpectedEOF;
  182.                     exit;
  183.                 end;
  184.             end;
  185.             bitsleft := 0;
  186.         end;
  187.         thiscode := b[p];
  188.         currentcode := codesize + bitsleft;
  189.         if currentcode <=8 then
  190.         begin
  191.             b[p] := b[p] shr codesize;
  192.             bitsleft := currentcode;
  193.         end else
  194.         begin
  195.             inc(p);
  196.             if p>=q then
  197.             begin
  198.                 blocksize := 0;
  199.                 blockread( F, blocksize, 1);
  200.                 if blocksize>0 then
  201.                 begin
  202.                     p:=0;
  203.                     blockread( F, b, blocksize, q );
  204.                     if q<>blocksize then
  205.                     begin
  206.                         freemem( firstcodestack, 4096 );
  207.                         freemem( lastcodestack, 4096 );
  208.                         freemem( codestack, 8192 );
  209.                         freemem( linebuffer, fi.width );
  210.                         UnpackImage := UnexpectedEOF;
  211.                         exit;
  212.                     end;
  213.                 end else
  214.                 begin
  215.                     freemem( firstcodestack, 4096 );
  216.                     freemem( lastcodestack, 4096 );
  217.                     freemem( codestack, 8192 );
  218.                     freemem( linebuffer, fi.width );
  219.                     UnpackImage := UnexpectedEOF;
  220.                     exit;
  221.                 end;
  222.             end;
  223.             thiscode := thiscode or ( b[p] shl (8-bitsleft) );
  224.             if currentcode <= 16 then
  225.             begin
  226.                 bitsleft := currentcode - 8;
  227.                 b[p] := b[p] shr bitsleft;
  228.             end else
  229.             begin
  230.                 inc(p);
  231.                 if p>=q then
  232.                 begin
  233.                     blocksize := 0;
  234.                     blockread( F, blocksize, 1);
  235.                     if blocksize>0 then
  236.                     begin
  237.                         p:=0;
  238.                         blockread( F, b, blocksize, q );
  239.                         if q<>blocksize then
  240.                         begin
  241.                             freemem( firstcodestack, 4096 );
  242.                             freemem( lastcodestack, 4096 );
  243.                             freemem( codestack, 8192 );
  244.                             freemem( linebuffer, fi.width );
  245.                             UnpackImage := UnexpectedEOF;
  246.                             exit;
  247.                         end;
  248.                     end else
  249.                     begin
  250.                         freemem( firstcodestack, 4096 );
  251.                         freemem( lastcodestack, 4096 );
  252.                         freemem( codestack, 8192 );
  253.                         freemem( linebuffer, fi.width );
  254.                         UnpackImage := UnexpectedEOF;
  255.                         exit;
  256.                     end;
  257.                 end;
  258.                 thiscode := thiscode or ( b[p] shl (16-bitsleft) );
  259.                 bitsleft := currentcode - 16;
  260.                 b[p] := b[p] shr bitsleft;
  261.             end;
  262.         end;
  263.         thiscode := thiscode and wordmasktable[codesize];
  264.         currentcode := thiscode;
  265.         if thiscode = bits2+1 then break;
  266.         if thiscode > nextcode then
  267.         begin
  268.             freemem( firstcodestack, 4096 );
  269.             freemem( lastcodestack, 4096 );
  270.             freemem( codestack, 8192 );
  271.             freemem( linebuffer, fi.width );
  272.             UnpackImage := BadCode;
  273.             exit;
  274.         end;
  275.         if thiscode = bits2 then
  276.         begin
  277.             nextcode := bits2+2;
  278.             codesize := bits + 1;
  279.             codesize2 := 1 shl codesize;
  280.             oldtoken := NoCode;
  281.             OldCode := NoCode;
  282.             continue;
  283.         end;
  284.         u := 0;
  285.         if thiscode = nextcode then
  286.         begin
  287.             if oldcode = NoCode then
  288.             begin
  289.                 freemem( firstcodestack, 4096 );
  290.                 freemem( lastcodestack, 4096 );
  291.                 freemem( codestack, 8192 );
  292.                 freemem( linebuffer, fi.width );
  293.                 UnpackImage := BadFirstCode;
  294.                 exit;
  295.             end;
  296.             firstcodestack^[u] := oldtoken;
  297.             inc( u );
  298.             thiscode := oldcode;
  299.         end;
  300.         while thiscode >= bits2 do
  301.         begin
  302.             firstcodestack^[u] := lastcodestack^[thiscode];
  303.             inc( u );
  304.             thiscode := codestack^[thiscode];
  305.         end;
  306.         oldtoken := thiscode;
  307.         while true do
  308.         begin
  309.             linebuffer^[byt] := thiscode;
  310.             inc( byt );
  311.             if byt >= fi.width then
  312.             begin
  313.                 GifOutLineProc( linebuffer^, line, fi.width );
  314.                 byt := 0;
  315.                 if fi.flags and $40 = $40 then
  316.                 begin
  317.                     line := line + inctable[pass];
  318.                     if line >= fi.depth then
  319.                     begin
  320.                         inc(pass);
  321.                         line := starttable[pass];
  322.                     end;
  323.                 end else inc(line);
  324.             end;
  325.             if u <= 0 then break;
  326.             dec( u );
  327.             thiscode := firstcodestack^[u];
  328.         end;
  329.         if (nextcode < 4096) and (oldcode <> NoCode) then
  330.         begin
  331.             codestack^[nextcode] := oldcode;
  332.             lastcodestack^[nextcode] := oldtoken;
  333.             inc( nextcode );
  334.             if (nextcode >= codesize2) and (codesize < 12) then
  335.             begin
  336.                 inc( codesize );
  337.                 codesize2 := 1 shl codesize;
  338.             end;
  339.         end;
  340.         oldcode := currentcode;
  341.     end;
  342.     freemem( firstcodestack, 4096 );
  343.     freemem( lastcodestack, 4096 );
  344.     freemem( codestack, 8192 );
  345.     freemem( linebuffer, fi.width );
  346.     UnpackImage := GoodRead;
  347. end; { UnpackImage }
  348.  
  349. procedure SkipExtension( Var F : File );
  350. var
  351.     pt : PlainText;
  352.     cb : ControlBlock;
  353.     ap : Application;
  354.     i : integer;
  355.     a, n, c : byte;
  356.     r : word;
  357. begin
  358.     blockread( F, c, 1 );
  359.     case c of
  360.         $01 :
  361.             begin
  362.                 blockread( F, pt, sizeof( PlainText ) );
  363.                 blockread( F, n, 1 );
  364.                 while n > 0 do
  365.                 begin
  366.                     for i := 0 to n-1 do
  367.                         blockread( F, a, 1 );
  368.                     blockread( F, n, 1 );
  369.                 end;
  370.             end;
  371.         $F9 :
  372.             blockread( F, cb, sizeof( ControlBlock ) );
  373.         $FE :
  374.             begin
  375.                 blockread( F, n, 1 );
  376.                 while n > 0 do
  377.                 begin
  378.                     for i:= 0 to n-1 do
  379.                         blockread( F, a, 1 );
  380.                     blockread( F, n, 1 );
  381.                 end;
  382.             end;
  383.         $FF :
  384.             begin
  385.                 blockread( F, ap, sizeof( Application ) );
  386.                 blockread( F, n, 1 );
  387.                 while n > 0 do
  388.                 begin
  389.                     for i := 0 to n-1 do
  390.                         blockread( F, a, 1 );
  391.                     blockread( F, n, 1 );
  392.                 end;
  393.             end;
  394.         else
  395.             begin
  396.                 blockread( F, n, 1 );
  397.                 for i := 0 to n-1 do
  398.                         blockread( F, a, 1 );
  399.             end;
  400.     end;
  401. end; { SkipExtension }
  402.  
  403. function UnpackGIF( Var F : File ) : integer;
  404. var
  405.     gh : GifHeader;
  406.     iblk : ImageBlock;
  407.     t : longint;
  408.     b, c : integer;
  409.     r : word;
  410.     ch : char;
  411.     fi : FileInfo;
  412. begin
  413.     blockread( F, gh, SizeOf(GifHeader), r );
  414.     if ( gh.sig[1]+gh.sig[2]+gh.sig[3]<>'GIF' ) or ( r<>SizeOf(GifHeader) ) then
  415.     begin
  416.         UnpackGIF := BadFile;
  417.         exit;
  418.     end;
  419.     fi.width := gh.screenwidth;
  420.     fi.depth := gh.screendepth;
  421.     fi.bits := gh.flags and $07 + 1;
  422.     fi.background := gh.background;
  423.     if ( gh.flags and $80 )=$80 then
  424.     begin
  425.         c:=3*( 1 shl fi.bits );
  426.         blockread( F, fi.palette, c, r );
  427.         if r<>c then
  428.         begin
  429.             UnpackGIF := BadRead;
  430.             exit;
  431.         end;
  432.         for b := 0 to 255 do
  433.         begin
  434.             GIFPalette[b*3] := fi.palette[b*3+1] shr 2;
  435.             GIFPalette[b*3+1] := fi.palette[b*3+2] shr 2;
  436.             GIFPalette[b*3+2] := fi.palette[b*3+3] shr 2;
  437.         end;
  438.  
  439.     end;
  440.     blockread( F, ch, 1 );
  441.     while ( ch = ',' ) or ( ch = '!' ) or ( ch = #0 ) do
  442.     begin
  443.         case ch of
  444.             ',' : begin
  445.                             blockread( F, iblk, SizeOf(ImageBlock), r );
  446.                             if r<>SizeOf(ImageBlock) then
  447.                             begin
  448.                                 UnpackGIF := BadRead;
  449.                                 Exit;
  450.                             end;
  451.                             fi.width := iblk.width;
  452.                             fi.depth := iblk.depth;
  453.                             if ( iblk.flags and $80 )=$80 then
  454.                             begin
  455.                                 b := 3*(1 shl (iblk.flags and $07 + 1));
  456.                                 blockread( F, fi.palette, b, r );
  457.                                 if r<>b then
  458.                                 begin
  459.                                     UnpackGIF := BadRead;
  460.                                     Exit;
  461.                                 end;
  462.                                 for b := 0 to 255 do
  463.                                 begin
  464.                                     GIFPalette[b*3] := fi.palette[b*3+1] shr 2;
  465.                                     GIFPalette[b*3+1] := fi.palette[b*3+2] shr 2;
  466.                                     GIFPalette[b*3+1] := fi.palette[b*3+3] shr 2;
  467.                                 end;
  468.                             end;
  469.                             if EOF( F ) then
  470.                             begin
  471.                                 UnpackGIF := BadFile;
  472.                                 Exit;
  473.                             end;
  474.                             c:=0;
  475.                             blockread( F, c, 1 );
  476.                             fi.flags:=iblk.flags;
  477.                             t := UnpackImage( F, c, fi );
  478.                             UnpackGif:=t;
  479.                             exit;
  480.                         end;
  481.             '!' : SkipExtension( F );
  482.         end;
  483.     end;
  484. end; { UnpackGIF }
  485.  
  486. function LoadGif;
  487. var
  488.     D: DirStr;
  489.     N: NameStr;
  490.     E: ExtStr;
  491.     FileHandle : File;
  492. begin
  493.     FSplit( F, D, N, E );
  494.     if E='' then E:='.GIF';
  495.     F := D+N+E;
  496.     {$I-}
  497.         assign( FileHandle, F );
  498.         reset( FileHandle, 1 );
  499.     {$I+}
  500.     if ioresult = 0 then
  501.         LoadGif := UnpackGif( FileHandle )
  502.     else
  503.         LoadGif := NoFile;
  504.     {$I-}
  505.         close( FileHandle );
  506.     {$I+}
  507. end; { LoadGif }
  508.  
  509. function WriteScreenDesc( var fp : file; width, depth, bits, background : integer; var palette ) : integer;
  510. var
  511.     gh : GIFHeader;
  512.     i : integer;
  513.     gifsig : string;
  514.     pal : TByteArray absolute palette;
  515.     a : byte;
  516. begin
  517.     FillChar( gh, sizeof(GIFHeader),0 );
  518.     gifsig := 'GIF87a';
  519.     move( gifsig[1], gh.sig[1], 6 );
  520.     gh.screenwidth := width;
  521.     gh.screendepth := depth;
  522.     gh.background := background;
  523.     gh.aspect := 0;
  524.     gh.flags := $80 or ((bits-1) shl 4) or ((bits-1) and $07);
  525.     blockwrite( fp, gh, sizeof(GIFHeader) );
  526.     for i := 0 to (1 shl bits)*3-1 do
  527.     begin
  528.         a := pal[i] shl 2;
  529.         blockwrite( fp, a, 1 );
  530.     end;
  531.     WriteScreenDesc := 0;
  532. end;
  533.  
  534. function WriteImageDesc( var fp : file; left, top, width, depth, bits : integer ) : integer;
  535. var
  536.     ib : ImageBlock;
  537.     ch : char;
  538. begin
  539.     fillchar( ib, sizeof(ImageBlock), 0 );
  540.     ch := ',';
  541.     blockwrite( fp, ch, 1 );
  542.     ib.left := left;
  543.     ib.top := top;
  544.     ib.width := width;
  545.     ib.depth := depth;
  546.     ib.flags := bits-1;
  547.     blockwrite( fp, ib, sizeof(ImageBlock) );
  548.     WriteImageDesc := 0;
  549. end;
  550.  
  551.  
  552. function CompressImage( var fp : file; mincodesize : word ) : integer;
  553. var
  554.     prefixcode, suffixchar, hx, d : integer;
  555.     codebuffer, newcode : ^TByteArray;
  556.     oldcode, currentcode : ^TIntArray;
  557.     codesize, clearcode, eofcode, bitoffset,
  558.     byteoffset, bitsleft, maxcode, freecode : integer;
  559.  
  560.  
  561.     procedure InitTable( mincodesize : integer );
  562.     var
  563.         i : integer;
  564.     begin
  565.         codesize := mincodesize + 1;
  566.         clearcode := 1 shl mincodesize;
  567.         eofcode := clearcode+1;
  568.         freecode := clearcode+2;
  569.         maxcode := 1 shl codesize;
  570.         for i := 0 to tablesize-1 do
  571.             currentcode^[i] := 0;
  572.     end;
  573.  
  574.     procedure Deallocate;
  575.     begin
  576.         freemem( newcode, tablesize+1 );
  577.         freemem( currentcode, (tablesize+1)*2 );
  578.         freemem( oldcode, (tablesize+1)*2 );
  579.         freemem( codebuffer, 260 );
  580.     end;
  581.  
  582.     procedure FlushFile( var fp : file; n : integer );
  583.     var
  584.         a : byte;
  585.     begin
  586.         a := n;
  587.         blockwrite( fp, a, 1 );
  588.         blockwrite( fp, codebuffer^[0], n );
  589.     end;
  590.  
  591.     procedure WriteCode( var fp : file; code : integer );
  592.     var
  593.         temp : longint;
  594.     begin
  595.         byteoffset := bitoffset shr 3;
  596.         bitsleft := bitoffset and 7;
  597.         if byteoffset >= 254 then
  598.         begin
  599.             FlushFile( fp, byteoffset );
  600.             codebuffer^[0] := codebuffer^[byteoffset];
  601.             bitoffset := bitsleft;
  602.             byteoffset := 0;
  603.         end;
  604.         if bitsleft > 0 then
  605.         begin
  606.             temp := ( longint(code) shl bitsleft ) or codebuffer^[byteoffset];
  607.             codebuffer^[byteoffset] := temp;
  608.             codebuffer^[byteoffset+1] := temp shr 8;
  609.             codebuffer^[byteoffset+2] := temp shr 16;
  610.         end else
  611.         begin
  612.             codebuffer^[byteoffset] := code;
  613.             codebuffer^[byteoffset+1] := code shr 8;
  614.         end;
  615.         bitoffset := bitoffset + codesize;
  616.     end;
  617.  
  618.  
  619. begin
  620.     if (mincodesize<2) or (mincodesize>9) then
  621.         if mincodesize = 1 then
  622.             mincodesize := 2
  623.         else
  624.         begin
  625.             CompressImage := 1;
  626.             exit;
  627.         end;
  628.     getmem( codebuffer, 260 );
  629.     getmem( oldcode, (tablesize+1)*2 );
  630.     getmem( currentcode, (tablesize+1)*2 );
  631.     getmem( newcode, tablesize+1 );
  632.     bitoffset := 0;
  633.     InitTable( mincodesize );
  634.     blockwrite( fp, mincodesize, 1 );
  635.     suffixchar := GIFInPixelProc;
  636.     if suffixchar < 0 then
  637.     begin
  638.         CompressImage := 1;
  639.         Deallocate;
  640.         exit;
  641.     end;
  642.     prefixcode := suffixchar;
  643.     suffixchar := GIFInPixelProc;
  644.     while suffixchar<>-1 do
  645.     begin
  646.         hx := (prefixcode xor (suffixchar shl 5)) mod tablesize;
  647.         d := 1;
  648.         while true do
  649.         begin
  650.             if currentcode^[hx] = 0 then
  651.             begin
  652.                 writecode( fp, prefixcode );
  653.                 d := freecode;
  654.                 if freecode <= largestcode then
  655.                 begin
  656.                     oldcode^[hx] := prefixcode;
  657.                     newcode^[hx] := suffixchar;
  658.                     currentcode^[hx] := freecode;
  659.                     inc(freecode);
  660.                 end;
  661.                 if d=maxcode then
  662.                 begin
  663.                     if codesize<12 then
  664.                     begin
  665.                         inc(codesize);
  666.                         maxcode := maxcode shl 1;
  667.                     end else
  668.                     begin
  669.                         writecode( fp, clearcode );
  670.                         InitTable( mincodesize );
  671.                     end;
  672.                 end;
  673.                 prefixcode := suffixchar;
  674.                 break;
  675.             end;
  676.             if (oldcode^[hx] = prefixcode) and (newcode^[hx] = suffixchar ) then
  677.             begin
  678.                 prefixcode := currentcode^[hx];
  679.                 break;
  680.             end;
  681.             hx := hx + d;
  682.             d := d + 2;
  683.             if hx >= tablesize then hx := hx- tablesize;
  684.         end;
  685.         suffixchar := GIFInPixelProc;
  686.     end;
  687.     writecode( fp, prefixcode );
  688.     writecode( fp, eofcode );
  689.     if bitoffset >0 then FlushFile( fp, (bitoffset+7) div 8 );
  690.     FlushFile( fp, 0 );
  691.     CompressImage := 0;
  692.     Deallocate;
  693. end;
  694.  
  695.  
  696. function WriteGif( var fp : file; width, depth, bits : integer; var palette ) : integer;
  697. var
  698.     ch : char;
  699. begin
  700.     if WriteScreenDesc( fp, width, depth, bits, 0, palette )>0 then
  701.         WriteGIF := 1
  702.     else
  703.     if WriteImageDesc( fp, 0, 0, width, depth, bits )>0 then
  704.         WriteGIF := 2
  705.     else
  706.     if CompressImage( fp, bits )>0 then
  707.         WriteGIF := 3
  708.     else
  709.     begin
  710.         WriteGIF := 0;
  711.         ch := ';';
  712.         blockwrite( fp, ch, 1 );
  713.     end;
  714. end;
  715.  
  716. function SaveGif( f : string; width, depth, bits : integer; var palette ) : integer;
  717. var
  718.     D: DirStr;
  719.     N: NameStr;
  720.     E: ExtStr;
  721.     FileHandle : File;
  722. begin
  723.     FSplit( F, D, N, E );
  724.     if E='' then E:='.GIF';
  725.     F := D+N+E;
  726.     {$I-}
  727.         assign( FileHandle, F );
  728.         rewrite( FileHandle, 1 );
  729.     {$I+}
  730.     if ioresult = 0 then
  731.         SaveGif := WriteGif( FileHandle, width, depth, bits, palette  )
  732.     else
  733.         SaveGif := NoFile;
  734.     {$I-}
  735.         close( FileHandle );
  736.     {$I+}
  737. end;
  738.  
  739. function GifError;
  740. begin
  741.     case ErrorCode of
  742.         GoodRead : GifError := 'Ok';
  743.         BadFile  : GifError := 'Bad File';
  744.         BadRead  : GifError := 'Bad Read';
  745.         UnexpectedEOF : GifError := 'Unexpected End';
  746.         BadCode       : GifError := 'Bad LZW Code';
  747.         BadFirstCode  : GifError := 'Bad First Code';
  748.         BadSymbolSize : GifError := 'Bad Symbol Size';
  749.         NoFile        : GifError := 'File Not Found';
  750.         else GifError := 'Unknown';
  751.     end;
  752. end; { GifError }
  753.  
  754.  
  755. end.
  756.